package mail;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.util.Formatter;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;

import crypto.DigestManager;
import crypto.EncryptionManager;
import crypto.KeyMaker;
import crypto.SignatureManager;

public class CryptoMail 
{
	//http://www.gnu.org/software/gnu-crypto/manual/api/index.html
	
	
	
	public CryptoMail()
	{
		
	}

	public static Multipart encriparYFirmarMensaje(Message mensaje) throws IOException, MessagingException, InvalidKeyException, IllegalStateException 
	{
//		KeyMaker.generateAES();
		Multipart multipart = new MimeMultipart();
		
		MimeBodyPart partDigest = new MimeBodyPart();
		MimeBodyPart partCrypt = new MimeBodyPart();
		MimeBodyPart partHMAC = new MimeBodyPart();
		MimeBodyPart partFirma = new MimeBodyPart();
		
		String contenido = Correo.getInstance().darContenidoMensaje(mensaje);
		String digest = getHex((DigestManager.generarDigest(contenido.getBytes())));
		partDigest.setContent(digest,"text/plain");
		multipart.addBodyPart(partDigest);
		
		multipart.addBodyPart(partDigest);
		byte[] contenidoCrypt = EncryptionManager.encriptar(contenido.getBytes(), EncryptionManager.RUTA_LLAVE);
		String contEncriptString = getHex(contenidoCrypt);
		
		partCrypt.setContent(contEncriptString,"text/plain");
		multipart.addBodyPart(partCrypt);
		
		byte[] HMAC = DigestManager.generateHMAC(contenidoCrypt, DigestManager.RUTA_LLAVE);
		byte [] HMACFirmado = SignatureManager.firmar(HMAC, SignatureManager.RUTA_PRIV);
		
		partHMAC.setContent(getHex(HMAC), "text/plain");
		multipart.addBodyPart(partHMAC);
		
		partFirma.setContent(getHex(HMACFirmado), "text/plain");
		multipart.addBodyPart(partFirma);
		
		multipart.addBodyPart(Correo.getInstance().adjuntar(SignatureManager.RUTA_PUB));
		
		System.out.println(contenido+          "contenido");
		System.out.println(new String (contenidoCrypt) + "CONTENIDO ENCRYPT STRING");
		System.out.println(getHex(contenidoCrypt) + "CONTENIDO ENCRIPT HEX");
		
		//mp[0] = digest
		//mp[1] = contEncriptado
		//mp[2] = HMAC (contEncriptado)
		//mp[3] = Firma (HMAC)
		//mp[4] = KeySig
		return multipart; 
	}
	
	public static Multipart encriptarMensaje(Message mensaje) throws IOException, MessagingException, InvalidKeyException, IllegalStateException 
	{
		
		MimeMultipart multipart = new MimeMultipart();
		MimeBodyPart partDigest = new MimeBodyPart();
		MimeBodyPart partCrypt = new MimeBodyPart();
		String contenido = Correo.getInstance().darContenidoMensaje(mensaje);
		String digest = getHex((DigestManager.generarDigest(contenido.getBytes())));
		partDigest.setContent(digest,"text/plain");
		
		multipart.addBodyPart(partDigest);
		byte[] contenidoCrypt = EncryptionManager.encriptar(contenido.getBytes(), EncryptionManager.RUTA_LLAVE);
		String contEncriptString = getHex(contenidoCrypt);
		
		partCrypt.setContent(contEncriptString,"text/plain");
		multipart.addBodyPart(partCrypt);
		
		System.out.println(contenido+          "contenido");
		System.out.println(new String (contenidoCrypt) + "CONTENIDO ENCRYPT STRING");
		System.out.println(getHex(contenidoCrypt) + "CONTENIDO ENCRIPT HEX");
		
		//mp[0] = digest
		//mp[1] = contEncriptado
		return multipart;
	
	}
	
	public static Multipart firmarMensajeHMAC(byte[] contenido) throws InvalidKeyException, IllegalStateException, IOException, MessagingException
	{
		Multipart mp = new MimeMultipart();
		
		MimeBodyPart partHMAC = new MimeBodyPart();
		MimeBodyPart partFirma = new MimeBodyPart();
		MimeBodyPart partDatos = new MimeBodyPart();
		byte[] HMAC = DigestManager.generateHMAC(contenido, DigestManager.RUTA_LLAVE);
		byte [] HMACFirmado = SignatureManager.firmar(HMAC, SignatureManager.RUTA_PRIV);
		partDatos.setContent(getHex(contenido), "text/plain");
		partHMAC.setContent(getHex(HMAC), "text/plain");
		mp.addBodyPart(partHMAC);
		
		partFirma.setContent(getHex(HMACFirmado), "text/plain");
		mp.addBodyPart(partFirma);
		
		mp.addBodyPart(Correo.getInstance().adjuntar(SignatureManager.RUTA_PUB));
		mp.addBodyPart(partDatos);
		
		
		//mp[0] = HMAC
		//mp[1] = Firma
		//mp[2] = Key
		//mp[3] = Datos
		return mp;
	}
	
	public static Multipart firmarMensaje(byte[] mensaje) throws InvalidKeyException, IllegalStateException, IOException, MessagingException
	{
		Multipart mp = new MimeMultipart();
		
		MimeBodyPart partFirma = new MimeBodyPart();

		MimeBodyPart partDatos = new MimeBodyPart();
		byte [] firma = SignatureManager.firmar(mensaje, SignatureManager.RUTA_PRIV);
		
		partFirma.setContent(getHex(firma), "text/plain");
		mp.addBodyPart(partFirma);
		partDatos.setContent(getHex(mensaje), "text/plain");
		mp.addBodyPart(Correo.getInstance().adjuntar(SignatureManager.RUTA_PUB));
		mp.addBodyPart(partDatos);
		//mp[0] = datos
		//mp[1] = Firma
		//mp[2] = Key
		return mp;
	}
	
	
	
	
	
	
	
		
	public static String desencriptarMensaje (Object contenido) throws IOException, MessagingException, InvalidKeyException, IllegalStateException 
	{
			Multipart multipart = (Multipart)contenido;

			Part parte1 = multipart.getBodyPart(0);
			Part parte2 = multipart.getBodyPart(1);
			byte[] desencriptados = EncryptionManager.desencriptar(getByteArray(parte2.getContent().toString()),EncryptionManager.RUTA_LLAVE);

			System.out.println(getHex(desencriptados)+ "     DESENCRIPTADOS HEX  ");
			System.out.println(new String(desencriptados)+ "     DESENCRIPTADOS STRING  ");
			System.out.println(parte1.getContent().toString()+"       DIGEST HEX ENCRIPT");
			System.out.println(getHex(DigestManager.generarDigest(desencriptados))+ "    DIGEST HEX DESENCRIPT");
			
//			if(DigestManager.verificarDigest(getByteArray(parte1.getContent().toString()), desencriptados))
//			{
				return (new String(desencriptados));
				
				//TODO quitar para activar el digest cuando se tenga bn el encriptar
//			}
//			else
//				return "No se pudo verificar el digest";	
	}
	
	public static String verificarMensajeFirmado(Object contenido) throws MessagingException, IOException
	{
		Multipart multipart = (Multipart)contenido;

		Part parte1 = multipart.getBodyPart(0);
		Part parte2 = multipart.getBodyPart(1);
		Part parte3 = multipart.getBodyPart(2);
		
		if(SignatureManager.verificarFirma(getByteArray(parte3.getContent().toString()), getByteArray(parte1.getContent().toString()), (InputStream)parte2.getContent()))
			return new String (getByteArray(parte3.getContent().toString()));
		return "no se pudo verificar la firma del mensage";
	}
	
	public static String verificarMensajeEncriptadoFirmado(Object contenido) throws MessagingException, IOException, InvalidKeyException, IllegalStateException
	{
		Multipart multipart = (Multipart)contenido;
		Multipart multipart2 = new MimeMultipart();
		MimeBodyPart parteHMAC = (MimeBodyPart) multipart.getBodyPart(2);
//		DigestManager.verificarHMACDigest(actual, datos, rutaLlave)
		MimeBodyPart parteFirma = (MimeBodyPart) multipart.getBodyPart(3);
		MimeBodyPart parteKey = (MimeBodyPart) multipart.getBodyPart(4);
		String cont = desencriptarMensaje(contenido)
;
		MimeBodyPart parteDatosDesencrypt = new MimeBodyPart();
		parteDatosDesencrypt.setContent(cont, "text/plain");
		multipart2.addBodyPart(parteFirma);
		multipart2.addBodyPart(parteKey);
		multipart2.addBodyPart(parteDatosDesencrypt);
		 return verificarMensajeFirmado(multipart2);
	}
	
	
	public static String verificarMensajeEncriptadoFirmadoHMAC(Object contenido) throws MessagingException, IOException, InvalidKeyException, IllegalStateException
	{
		Multipart multipart = (Multipart)contenido;
		Multipart multipart2 = new MimeMultipart();
		MimeBodyPart parte1 = (MimeBodyPart) multipart.getBodyPart(2);
		MimeBodyPart parte2 = (MimeBodyPart) multipart.getBodyPart(3);
		String cont = desencriptarMensaje(contenido)
;
		MimeBodyPart parte3 = new MimeBodyPart();
		parte3.setContent(cont, "text/plain");
		multipart2.addBodyPart(parte1);
		multipart2.addBodyPart(parte2);
		multipart2.addBodyPart(parte3);
		 return verificarMensajeFirmado(multipart2);
	}
	
	
	
	public static String verificarMensajeFirmadoHMAC(Object multipart) {
		// TODO Auto-generated method stub
		return null;
	}
	
	
	
	public static byte[] getByteArray(String s) {
	    int len = s.length();
	    byte[] data = new byte[len / 2];
	    for (int i = 0; i < len; i += 2) {
	        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
	                             + Character.digit(s.charAt(i+1), 16));
	    }
	    return data;
	}

	
	public static String getHex(byte[] buf)
    {
        Formatter formatter = new Formatter();
        for (byte b : buf)
            formatter.format("%02x", b);
        return formatter.toString();
	}

	
}
